home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / admin / news / fixactive < prev    next >
Encoding:
AWK Script  |  1997-08-26  |  13.5 KB  |  404 lines

  1. #!/usr/local/bin/gawk -f
  2. # @(#) fixactive.gawk 1.2 94/10/15
  3. # 94/07/25 john h. dubois iii
  4. # 94/08/04 Added all options.
  5. # 94/09/29 More checks on validity of input.
  6. # 94/10/15 Added s option.
  7.  
  8. BEGIN {
  9.     Name = "fixactive"
  10.     Usage = "Usage: " Name " [-hnq] [-s<pattern>] template-file [active-file]"
  11.     ARGC = Opts(Name,Usage,"hnqs:",1)
  12.     if ("h" in Options) {
  13.     printf \
  14. "%s: fix active file by comparing it to a template file.\n"\
  15. "%s\n"\
  16. "Any groups in template-file that are not in the active file are added,\n"\
  17. "with the same status as they have in the template file.\n"\
  18. "Any groups in the active file that are not in template-file are removed.\n"\
  19. "The new active file is written to the standard output.\n"\
  20. "Options:\n"\
  21. "-h: Print this help.\n"\
  22. "-n: Do not delete any groups from the active file even if they aren't\n"\
  23. "    in template-file.\n"\
  24. "-s<pattern>: Don't delete groups that match the given pattern even if they\n"\
  25. "    aren't in template-file.  This can be used to preserve local groups.\n"\
  26. "-q: Do not print notice line for each line added to the active file.\n",
  27. Name,Usage
  28.     exit
  29.     }
  30.     NoDel = "n" in Options
  31.     Quiet = "q" in Options
  32.     if ("s" in Options)
  33.     Save = Options["s"]
  34.     compare = ARGV[1]
  35.     if (ARGC > 2)
  36.     local = ARGV[2]
  37.     else
  38.     local = "/usr/lib/news/active"
  39.     while ((ret = (getline < compare)) == 1) {
  40.     sub("\015$","")    # lines sometimes end in cr
  41.     if (NF != 4)
  42.         printf "Error in template-file: Not enough fields:\n%s\n",
  43.         $0 > "/dev/stderr"
  44.     else if ($2 !~ /^[0-9]+$/ || $3 !~ /^[0-9]+$/)
  45.         # Check this even though it won't be used because it indicates
  46.         # a garbage line.
  47.         printf "Error in template-file: Bad article range:\n%s\n",
  48.         $0 > "/dev/stderr"
  49.     else if ($4 !~ /^([mynx]$|xm$|=)/)
  50.         printf "Error in template-file: Bad status:\n%s\n",
  51.         $0 > "/dev/stderr"
  52.     else
  53.         CompGrps[$1] = $0
  54.     }
  55.     if (ret) {
  56.     printf "Error reading template-file '%s'.  Exiting.\n",compare > \
  57.     "/dev/stderr"
  58.     exit 1
  59.     }
  60.     close(compare)
  61.     while ((ret = (getline < local)) == 1) {
  62.     if (NF == 4) {
  63.         if ($1 in CompGrps || NoDel) {
  64.         print $0
  65.         delete CompGrps[$1]
  66.         }
  67.         else if (Save != "" && $1 ~ Save) {
  68.         print $0
  69.         delete CompGrps[$1]
  70.         printf "Preserved group '%s'.\n",$1 | "cat 1>&2"
  71.         }
  72.         else
  73.         printf "%s did not exist in template-file.  Deleted.\n",
  74.         $1 | "cat 1>&2"
  75.     }
  76.     else
  77.         printf "Error in active file: Not enough fields:\n%s\n",
  78.         $0 > "/dev/stderr"
  79.     }
  80.     if (ret) {
  81.     printf "Error reading active file '%s'.  Exiting.\n",local > \
  82.     "/dev/stderr"
  83.     exit 1
  84.     }
  85.     for (Group in CompGrps) {
  86.     if (!Quiet)
  87.         printf "%s did not exist in local file.  Added.\n",
  88.         Group > "/dev/stderr"
  89.     split(CompGrps[Group],F)
  90.     printf "%s %s %s %s\n",Group,"0000000000","00001",F[4]
  91.     NumAdded++
  92.     }
  93.     printf "%d groups added from template-file.\n",NumAdded > "/dev/stderr"
  94. }
  95.  
  96. # @(#) ProcArgs 1.2.1 94/06/11
  97. # 92/02/29 john h. dubois iii (john@armory.com)
  98. # 93/07/18 Added "#" arg type
  99. # 93/09/26 Do not count -h against MinArgs
  100. # 94/01/01 Stop scanning at first non-option arg.  Added ">" option type.
  101. #          Removed meaning of "+" or "-" by itself.
  102. # 94/03/08 Added & option and *()< option types.
  103. # 94/04/02 Added NoRCopt to Opts()
  104. # 94/06/11 Mark numeric variables as such.
  105. # 94/07/08 Opts(): Don't require any args if 'h' option is given.
  106.  
  107. # optlist is a string which contains all of the possible command line options.
  108. # A character followed by certain characters indicates that the option takes
  109. # an argument, with type as follows:
  110. # :    String argument
  111. # *    Floating point argument
  112. # (    Non-negative floating point argument
  113. # )    Positive floating point argument
  114. # #    Integer argument
  115. # <    Non-negative integer argument
  116. # >    Positive integer argument
  117. # The only difference the type of argument makes is in the runtime argument
  118. # error checking that is done.
  119.  
  120. # The & option is a special case used to get numeric options without the
  121. # user having to give an option character.  It is shorthand for [-+.0-9].
  122. # If & is included in optlist and an option string that begins with one of
  123. # these characters is seen, the value given to "&" will include the first
  124. # char of the option.  & must be followed by a type character other than ":".
  125. # Note that if e.g. &> is given, an option of -.5 will produce an error.
  126.  
  127. # Strings in argv[] which begin with "-" or "+" are taken to be
  128. # strings of options, except that a string which consists solely of "-"
  129. # or "+" is taken to be a non-option string; like other non-option strings,
  130. # it stops the scanning of argv and is left in argv[].
  131. # An argument of "--" or "++" also stops the scanning of argv[] but is removed.
  132. # If an option takes an argument, the argument may either immediately
  133. # follow it or be given separately.
  134. # "-" and "+" options are treated the same.  "+" is allowed because most awks
  135. # take any -options to be arguments to themselves.  gawk 2.15 was enhanced to
  136. # stop scanning when it encounters an unrecognized option, though until 2.15.5
  137. # this feature had a bug that caused problems in some cases.
  138.  
  139. # If an option that does not take an argument is given,
  140. # an index with its name is created in Options and its value is set to "1".
  141. # If an option that does take an argument is given,
  142. # an index with its name is created in Options and its value
  143. # is set to the value of the argument given for it.
  144. # Options and their arguments are deleted from argv.
  145. # Note that this means that there may be gaps left in the indices of argv[].
  146. # If compress is nonzero, argv[] is packed by moving its elements so that
  147. # they have contiguous integer indices starting with 0.
  148. # argv[0] is not examined.
  149. # The number of arguments left in argc is returned.
  150. # If an error occurs, the global string OptErr is set to an error message
  151. # and -1 is returned.
  152. function ProcArgs(argc,argv,OptList,Options,compress,
  153. ArgNum,ArgsLeft,Arg,ArgLen,ArgInd,Option,Pos,NumOpt,Value,HadValue,
  154. NeedNextOpt)
  155. {
  156. # ArgNum is the index of the argument being processed.
  157. # ArgsLeft is the number of arguments left in argv.
  158. # Arg is the argument being processed.
  159. # ArgLen is the length of the argument being processed.
  160. # ArgInd is the position of the character in Arg being processed.
  161. # Option is the character in Arg being processed.
  162. # Pos is the position in OptList of the option being processed.
  163. # NumOpt is true if a numeric option may be given.
  164.     ArgsLeft = argc
  165.     NumOpt = index(OptList,"&")
  166.     for (ArgNum = 1; ArgNum < argc; ArgNum++) {
  167.     if ((Arg = argv[ArgNum]) !~ /^[-+]./)    # Not an option; quit
  168.         break
  169.     delete argv[ArgNum]
  170.     ArgsLeft--
  171.     if ((Arg == "--") || (Arg == "++"))
  172.         break
  173.     ArgLen = length(Arg)
  174.     for (ArgInd = 2; ArgInd <= ArgLen; ArgInd++) {
  175.         Option = substr(Arg,ArgInd,1)
  176.         if (NumOpt && Option ~ /[-+.0-9]/) {
  177.         Option = "&"
  178.         Arg = "&" Arg
  179.         ArgLen++
  180.         Pos = NumOpt
  181.         }
  182.         else if (!(Pos = index(OptList,Option)) || Option == "&") {
  183.         OptErr = "Invalid option: -" Option
  184.         return -1
  185.         }
  186.  
  187.         # Find what the value of the option will be if it needs one
  188.         if (NeedNextOpt = (ArgInd >= ArgLen)) # Value is the next arg
  189.         Value = argv[ArgNum+1]
  190.         else    # Value is included with option
  191.         Value = substr(Arg,ArgInd + 1)
  192.  
  193.         if (HadValue = AssignVal(Option,Value,Options,
  194.         substr(OptList,Pos + 1,1),ArgNum < (argc - 1))) {
  195.         if (HadValue == -1)
  196.             return -1
  197.         if (NeedNextOpt) {
  198.             delete argv[++ArgNum]
  199.             ArgsLeft--
  200.         }
  201.         break    # Used up this option
  202.         }
  203.     }
  204.     }
  205.     if (compress != 0)
  206.     PackArr(argv,ArgsLeft)
  207.     return ArgsLeft
  208. }
  209.  
  210. # Global variables: OptErr
  211. # Return value: -1 on error, 0 if option did not require an argument,
  212. # 1 if it did.
  213. function AssignVal(Option,Value,Options,ArgType,GotValue,Name,
  214. UsedValue,Err) {
  215.     # If option takes a value...
  216.     if (UsedValue = (ArgType ~ "[:*()#<>]")) {
  217.     if (!GotValue) {
  218.         if (Name != "")
  219.         OptErr = "Variable requires a value -- " Name
  220.         else
  221.         OptErr = "option requires an argument -- " Option
  222.         return -1
  223.     }
  224.     if ((Err = CheckType(ArgType,Value,Option,Name)) != "") {
  225.         OptErr = Err
  226.         return -1
  227.     }
  228.     # Mark this as a numeric variable; will be propogated to Options[] val.
  229.     if (ArgType != ":")
  230.         Value += 0
  231.     }
  232.     else
  233.     Value = 1
  234.     if (!(Option in Options))    # Do not overwrite previously assigned values
  235.     Options[Option] = Value
  236.     return UsedValue
  237. }
  238.  
  239. # Option is the option letter
  240. # Value is the value being assigned
  241. # Name is the var name of the option, if any
  242. # ArgType is one of:
  243. # :    String argument
  244. # *    Floating point argument
  245. # (    Non-negative floating point argument
  246. # )    Positive floating point argument
  247. # #    Integer argument
  248. # <    Non-negative integer argument
  249. # >    Positive integer argument
  250. # Returns null on success, err string on error
  251. function CheckType(ArgType,Value,Option,Name,  Err) {
  252.     if (ArgType == ":")
  253.     return ""
  254.     # A number begins with option + or -, and is followed by a string of
  255.     # digits or a decimal with digits before it, after it, or both
  256.     if (Value !~ /^[-+]?([0-9]+|[0-9]+?\.[0-9]+|[0-9]+\.)$/)
  257.     Err = "must be a number"
  258.     else if (ArgType ~ "[#<>]" && Value ~ /\./)
  259.     Err = "may not include a fraction"
  260.     else if (ArgType ~ "[()<>]" && Value < 0)
  261.     Err = "may not be negative"
  262.     else if (ArgType ~ "[)>]" && Value == 0)
  263.     Err = "must be a positive number"
  264.     if (Err != "") {
  265.     if (Name != "")
  266.         return "Value assigned to variable " Name " " Err
  267.     else {
  268.         if (Option == "&")
  269.         Option = Value
  270.         return "Value assigned to option -" Option " " Err
  271.     }
  272.     }
  273.     else
  274.     return ""
  275. }
  276.  
  277. # Packs Arr to indices starting with 0
  278. # Num should be the number of elements in Arr
  279. function PackArr(Arr,Num,  NewInd,OldInd) {
  280.     NewInd = OldInd = 0
  281.     for (; Num; Num--) {
  282.     while (!(OldInd in Arr))
  283.         OldInd++
  284.     if (NewInd != OldInd) {
  285.         Arr[NewInd] = Arr[OldInd]
  286.         delete Arr[OldInd]
  287.     }
  288.     OldInd++
  289.     NewInd++
  290.     }
  291. }
  292.  
  293. # Note: only the above functions are needed by ProcArgs.
  294. # The rest of these functions call ProcArgs() and also do other
  295. # option-processing stuff.
  296.  
  297. # Opts: Process command line arguments.
  298. # Opts processes command line arguments using ProcArgs()
  299. # and checks for errors.  If an error occurs, a message is printed
  300. # and the program is exited.
  301. #
  302. # Input variables:
  303. # Name is the name of the program, for error messages.
  304. # Usage is a usage message, for error messages.
  305. # OptList the option description string, as used by ProcArgs().
  306. # MinArgs is the minimum number of non-option arguments that this
  307. # program should have, non including ARGV[0] and +h.
  308. # If the program does not require any non-option arguments,
  309. # MinArgs should be omitted or given as 0.
  310. # rcFile, if given, is the name of a file to read for variable initialization.
  311. # Values given in it will not override values given on the command line.
  312. # VarNames is a comma-separated list of variable names to map to options,
  313. # in the same order as the options are given in OptList.
  314. # If UseEnv is given and nonzero, the variables will also be searched for in
  315. # the environment.  Values given in the environment will override those given
  316. # in the rcfile but not those given on the command line.
  317. # NoRCopt, if given, is an additional letter option that if given on the
  318. # command line prevents the rcfile from being read.
  319. # Special options:
  320. # If x is made an option and is given, some debugging info is output.
  321. # h is assumed to be the help option.
  322.  
  323. # Global variables:
  324. # The command line arguments are taken from ARGV[].
  325. # The arguments that are option specifiers and values are removed from
  326. # ARGV[], leaving only ARGV[0] and the non-option arguments.
  327. # The number of elements in ARGV[] should be in ARGC.
  328. # After processing, ARGC is set to the number of elements left in ARGV[].
  329. # The option values are put in Options[].
  330. # On error, Err is set to 1 so it can be checked for in an END block.
  331.  
  332. # Return value: The number of elements left in ARGV is returned.
  333.  
  334. function Opts(Name,Usage,OptList,MinArgs,rcFile,VarNames,UseEnv,NoRCopt,
  335. ArgsLeft) {
  336.     if (MinArgs == "")
  337.     MinArgs = 0
  338.     ArgsLeft = ProcArgs(ARGC,ARGV,OptList NoRCopt,Options,1)
  339. #    if ((ArgsLeft + ("h" in Options)) < (MinArgs+1)) {
  340.     if (ArgsLeft < (MinArgs+1) && !("h" in Options)) {
  341.     if (ArgsLeft != -1)
  342.         OptErr = "Not enough arguments"
  343.     print Name ": " OptErr ".  Use -h for help."
  344.     print Usage
  345.     Err = 1
  346.     exit 1
  347.     }
  348.     if (rcFile != "" && (NoRCopt == "" || !(NoRCopt in Options)) &&
  349.     InitOpts(rcFile,Options,OptList,VarNames,UseEnv) == -1)
  350.     {
  351.     print Name ": " OptErr ".  Use -h for help."
  352.     Err = 1
  353.     exit 1
  354.     }
  355.     return ArgsLeft
  356. }
  357.  
  358. # Global vars: sets OptErr; uses ENVIRON[];
  359. # if anything is read from the rcFile, sets READ_RCFILE to 1
  360. function InitOpts(rcFile,Options,OptTypes,VarNames,UseEnv,
  361. Line,Var,Pos,Vars,Map,CharOpt,NumVars,TypesInd,Types,Type,Ret) {
  362.     NumVars = split(VarNames,Vars,",")
  363.     TypesInd = Ret = 0
  364.     for (i = 1; i <= NumVars; i++) {
  365.     Var = Vars[i]
  366.     CharOpt = substr(OptTypes,++TypesInd,1)
  367.     if (CharOpt ~ "^[:*()#<>&]$")
  368.         CharOpt = substr(OptTypes,++TypesInd,1)
  369.     Map[Var] = CharOpt
  370.     Types[Var] = Type = substr(OptTypes,TypesInd+1,1)
  371.     # Do not overwrite entries from environment
  372.     if (UseEnv && Var in ENVIRON && AssignVal(CharOpt,ENVIRON[Var],Options,
  373.     Type,1,Var) == -1)
  374.         return -1
  375.     }
  376.     if (rcFile ~ "^~/")
  377.     rcFile = ENVIRON["HOME"] substr(rcFile,2)
  378.     while ((getline Line < rcFile) == 1) {
  379.     READ_RCFILE = 1
  380.     if (Line !~ /^#/ && Line !~ "^[ \t]*$") {
  381.         if (Pos = index(Line,"="))
  382.         Var = substr(Line,1,Pos-1)
  383.         else
  384.         Var = Line    # If no value, var is entire line
  385.         if (Var in Map) {
  386.         if (AssignVal(Map[Var],substr(Line,Pos+1),Options,
  387.         Types[Var],Pos != 0,Var) == -1)
  388.             return -1
  389.         }
  390.         else {
  391.         OptErr = sprintf("Unknown var \"%s\" set in %s",Var,rcFile)
  392.         Ret = -1
  393.         }
  394.     }
  395.     }
  396.     if ("x" in Options)
  397.     for (Var in Map)
  398.         if (Map[Var] in Options)
  399.         printf "%s=%s\n",Var,Options[Map[Var]]
  400.         else
  401.         printf "%s not set\n",Var
  402.     return Ret
  403. }
  404.